package com.ansion.utils;

import com.ansion.log.VLog;
import com.ansion.utils.phone.CocoPhoneNumber;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import io.michaelrocks.libphonenumber.android.AsYouTypeFormatter;
import io.michaelrocks.libphonenumber.android.NumberParseException;
import io.michaelrocks.libphonenumber.android.PhoneNumberUtil;
import io.michaelrocks.libphonenumber.android.Phonenumber.PhoneNumber;

/**
 * 电话号码工具类
 * 将PhoneNumberUtils的使用全部收回到该类中
 */
public class PhoneNumberHelper2 {

	public static final int[] SPECIAL_COUNTRY_CODE_INT = {
		1242, 1246, 1264, 1268, 1284, 1340, 1345, 1441, 1473, 1649,
		1664, 1670, 1671, 1684, 1721, 1758, 1767, 1784, 1787, 1809,
		1829, 1849, 1868, 1869, 1876, 1939
	};

	public static final String UNKNOWN_COUNTRY = "ZZ";

	public static Map<Integer, String> regionMap = null;

	public static Set<String> supportRegion = null;

	static  {
		regionMap = new HashMap<Integer, String>();
		regionMap.put(1242, "BS");
		regionMap.put(1246, "BB");
		regionMap.put(1264, "AI");
		regionMap.put(1268, "AG");
		regionMap.put(1284, "VG");
		regionMap.put(1340, "VI");
		regionMap.put(1345, "KY");
		regionMap.put(1441, "BM");
		regionMap.put(1473, "GD");
		regionMap.put(1649, "TC");
		regionMap.put(1664, "MS");
		regionMap.put(1670, "MP");
		regionMap.put(1671, "GU");
		regionMap.put(1684, "AS");
		regionMap.put(1721, "SX");
		regionMap.put(1758, "LC");
		regionMap.put(1767, "DM");
		regionMap.put(1784, "VC");
		regionMap.put(1787, "PR");
		regionMap.put(1809, "TT");
		regionMap.put(1829, "DO");
		regionMap.put(1849, "DO");
		regionMap.put(1868, "TT");
		regionMap.put(1869, "KN");
		regionMap.put(1876, "JM");
		regionMap.put(1939, "PR");
	}


	private static PhoneNumberUtil util;
	private static PhoneNumberUtil getInstance() {
		if (util == null) {
			util = PhoneNumberUtil.createInstance(ResourceUtils.getContext());
		}

		return util;
	}

	/**
	 * 传入的phone必须是包含国家码的号码，如8615298765432
	 *
	 * @param phone
	 * @return
	 */
	public static PhoneNumber getNumber(long phone) {
		if (phone < 10000000) return null; // 号码至少7位
		String str = "+" + phone;

		try {
			PhoneNumber number = getInstance().parse(str, null);
			//if (!getInstance().isValidNumber(number)) return null;

			return number;
		} catch (NumberParseException e) {
			return null;
		}
	}

	public static PhoneNumber getNumber(String phone) {
		try {
			PhoneNumber number = getInstance().parse(phone, null);
			return number;
		} catch (NumberParseException e) {
			return null;
		}
	}

	/**
	 * 根据countrycode和phone获取PhoneNumber，如果phone是国际格式号码，countrycode可以不传。
	 * 当号码合法，则返回PhoneNumber实例
	 *
	 * @param countryCode
	 * @param phone
	 * @return
	 */
	public static PhoneNumber getNumber(int countryCode, String phone) {
		if (phone == null || phone.trim().isEmpty()) return null;

		String region = null;
		if (countryCode == 61 && phone.startsWith("0011")) {
			phone = "+" + phone.substring(4);
		} else if (phone.startsWith("00")) {
			phone = "+" + phone.substring(2);
		} else if (countryCode > 1000
				&& Arrays.binarySearch(SPECIAL_COUNTRY_CODE_INT, countryCode) >= 0
				&& phone.startsWith("011")) {
			phone = "+" + phone.substring(3);
		} else if (countryCode == 81 && phone.startsWith("010")) {
			phone = "+" + phone.substring(3);
		}  else if (!phone.startsWith("+")) {
			if (countryCode != 242 && countryCode != 225) phone = killZero(phone);

			if (countryCode > 1000) {
				if (Arrays.binarySearch(SPECIAL_COUNTRY_CODE_INT, countryCode) >= 0) {
					phone = "+" + countryCode + phone;
				} else {
					return null;
				}
			} else {
				region = getInstance()
						.getRegionCodeForCountryCode(countryCode);
				if ("ZZ".equalsIgnoreCase(region)) return null;
			}
		}

		try {

			PhoneNumber number = getInstance().parse(phone,
					region);

			return number;

		} catch (NumberParseException e) {
			return null;
		}
	}

	/**
	 * make number to be digits and clean the zeros before number.
	 *
	 * @param phone
	 * @return
	 */
	private static String killZero(String phone) {
		if(phone == null || phone.trim().isEmpty()) return null;

		String format = PhoneNumberUtil.normalizeDigitsOnly(phone);
		if(format.startsWith("0")) {
			return format.replaceFirst("[0]+", "");
		}

		return format;
	}

	/**
	 * 根据countrycode和phone判定号码是否合法，如果phone是国际格式号码，countrycode可以不传。
	 *
	 * @param countryCode
	 * @param phone
	 * @return
	 */
	public static boolean isValid(int countryCode, String phone) {
		PhoneNumber number = getNumber(countryCode, phone);
		return isValid(number);
	}

	/**
	 * 根据countrycode和phone判定号码是否合法，如果phone是国际格式号码，countrycode可以不传。
	 *

	 * @return
	 */
	public static boolean isValid(PhoneNumber number) {
		if (number != null) {
			return getInstance().isValidNumber(number);
		}

		return false;
	}

	/**
	 * 判定号码是否合法
	 *
	 * @param phone
	 * @return
	 */
	public static boolean isValid(long phone) {
		PhoneNumber number = getNumber(phone);
		return isValid(number);
	}

	/**
	 * 将号码数字化处理，并将号码前面所有0去掉
	 *
	 * @param phone
	 * @return
	 */
	public static String formatPhoneNumber(String phone) {
		if(phone == null || phone.trim().isEmpty()) return null;

		String format = PhoneNumberUtil.normalizeDigitsOnly(phone);

		return format;
	}

	/**
	 * 获取coconumber，如果不合法，则返回null
	 *
	 * @param number
	 * @return
	 */
	public static CocoPhoneNumber getCocoNumber(PhoneNumber number) {
		if (!isValid(number)) return null;

		CocoPhoneNumber coconumber = new CocoPhoneNumber();
		coconumber.countryCode = number.getCountryCode();
		coconumber.mobile = String.valueOf(number.getNationalNumber());

		String e164 = getInstance().format(number,
				PhoneNumberUtil.PhoneNumberFormat.E164);
		if (e164 != null) {
			coconumber.phone = PhoneNumberUtil.normalizeDigitsOnly(e164);
		} else {
            VLog.donly("OUT", "#######ERROR###### Failed to get the e164 string from a valid number: " + number);
			coconumber.phone = number.getCountryCode() + "" + number.getNationalNumber();
			e164 = "+" + coconumber.phone;
		}

		coconumber.e164 = e164;
		coconumber.international = getInstance().format(number,
				PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL);
		coconumber.national = getInstance().format(number,
				PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
		coconumber.region = getInstance()
				.getRegionCodeForNumber(number);

		return coconumber;
	}

	/**
	 * 获取coconumber，如果不合法，则返回null
	 *
	 * @param countryCode
	 * @param phone
	 * @return
	 */
	public static CocoPhoneNumber getCocoNumber(int countryCode, String phone) {
		return getCocoNumber(getNumber(countryCode, phone));
	}

	/**
	 * 获取coconumber
	 *
	 * @param phone 必须是包含国家码的号码，如8615298765432
	 * @return
	 */
	public static CocoPhoneNumber getCocoNumber(long phone) {
		return getCocoNumber(getNumber(phone));
	}

	/**
	 * 根据PhoneNumber获取含国家码的纯数字号码。如'+86 152 2152 7949'，得到的返回为长整形8615221527949
	 *
	 * @param number
	 * @return
	 */
	public static long getInternationalNumberWithoutPlusChar(PhoneNumber number) {
		if (number == null) return 0;

		try {
			// format international number to be e164 format
			String e164 = getInstance().format(number,
					PhoneNumberUtil.PhoneNumberFormat.E164);
			if (e164 != null) {
				return Long.valueOf(PhoneNumberUtil.normalizeDigitsOnly(e164));
			}
		} catch (NumberFormatException e) {
			return 0;
		}

		return 0;
	}

	/**
	 * 根据PhoneNumber获取含国家码的纯数字号码。如'+86 152 2152 7949'，得到的返回为长整形8615221527949
	 *
	 * @param countryCode
	 * @param phone
	 * @return
	 */
	public static long getInternationalNumberWithoutPlusChar(int countryCode, String phone) {
		return getInternationalNumberWithoutPlusChar(getNumber(countryCode, phone));
	}

	/**
	 * 根据PhoneNumber获取含国家码的纯数字号码。如'+86 152 2152 7949'，得到的返回为长整形8615221527949
	 *
	 * @param phone 必须是包含国家码的号码，如8615298765432
	 * @return
	 */
	public static long getInternationalNumberWithoutPlusChar(long phone) {
		return getInternationalNumberWithoutPlusChar(getNumber(phone));
	}

	/**
	 * 根据PhoneNumber获取国际格式的号码字符串
	 *
	 * @param number
	 * @return
	 */
	public static String getInternationalFormat(PhoneNumber number) {
		if (number == null) return null;
		return getInstance().format(number,
				PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL);
	}

	/**
	 * 获取国际格式的号码字符串
	 *
	 * @param countryCode
	 * @param phone
	 * @return
	 */
	public static String getInternationalFormat(int countryCode, String phone) {
		PhoneNumber number = getNumber(countryCode, phone);
		return getInternationalFormat(number);
	}

	/**
	 * 获取国际格式的号码字符串
	 *
	 * @param phone 必须是包含国家码的号码，如8615298765432
	 * @return
	 */
	public static String getInternationalFormat(long phone) {
		PhoneNumber number = getNumber(phone);
		return getInternationalFormat(number);
	}

	/**
	 * 根据PhoneNumber获取国内格式的号码字符串
	 *
	 * @param number
	 * @return
	 */
	public static String getNationalFormat(PhoneNumber number) {
		if (number == null) return null;
		return getInstance().format(number,
				PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
	}

	/**
	 * 获取国内格式的号码字符串
	 *
	 * @param countryCode
	 * @param phone
	 * @return
	 */
	public static String getNationalFormat(int countryCode, String phone) {
		PhoneNumber number = getNumber(countryCode, phone);
		return getNationalFormat(number);
	}

	/**
	 * 获取国内格式的号码字符串
	 *
	 * @param phone 必须是包含国家码的号码，如8615298765432
	 * @return
	 */
	public static String getNationalFormat(long phone) {
		PhoneNumber number = getNumber(phone);
		return getNationalFormat(number);
	}

	/**
	 * 获取E164格式的号码字符串
	 *
	 * @param countryCode
	 * @param phone
	 * @return
	 */
	public static String getE164Format(int countryCode, String phone) {
		PhoneNumber number = getNumber(countryCode, phone);
		return getE164Format(number);
	}

	/**
	 * 根据PhoneNumber获取E164格式的号码字符串
	 *
	 * @param number
	 * @return
	 */
	public static String getE164Format(PhoneNumber number) {
		if (number == null) return null;
		return getInstance().format(number,
				PhoneNumberUtil.PhoneNumberFormat.E164);
	}

	/**
	 * 获取E164格式的号码字符串
	 *
	 * @param phone 必须是包含国家码的号码，如8615298765432
	 * @return
	 */
	public static String getE164Format(long phone) {
		PhoneNumber number = getNumber(phone);
		return getE164Format(number);
	}


	/**
	 * 根据国家码获取countrycode，由于很多使用相同countrycode的国家的region并不相同
	 * 所以只是根据countrycode，获取的regioncode不一定准确。
	 * 比如countrycode=1时，可能是US，也可能是CA，但根据这个方法获取的regioncode就是为US
	 *
	 * @param countryCode
	 * @return 当countrycode不合法，无法获取regionCode时，返回ZZ
	 */
	public static String getRegionCodeForCountryCode(int countryCode) {
		return getInstance().getRegionCodeForCountryCode(countryCode);
	}

	/**
	 * 获取号码所属的国家/地区
	 * 例如国家码同样是+1，如果后续regioncode是514的，那么regioncode不是US，而是CA
	 * 如果regioncode不存在，返回null
	 *
	 * @param countryCode
	 * @param phone
	 * @return 当号码或者countrycode不合法时，返回null
	 */
	public static String getRegionCode2(int countryCode, String phone) {
		return getRegionCode(getNumber(countryCode, phone));
	}

	/**
	 * 获取号码所属的国家/地区
	 * 例如国家码同样是+1，如果后续regioncode是514的，那么regioncode不是US，而是CA
	 * 如果regioncode不存在，返回null
	 *
	 * @param phone 必须是包含国家码的号码，如8615298765432
	 * @return 当号码或者countrycode不合法时，返回null
	 */
	public static String getRegionCode2(long phone) {
		return getRegionCode(getNumber(phone));
	}

	/**
	 * 获取号码所属的国家/地区
	 * 例如国家码同样是+1，如果后续regioncode是514的，那么regioncode不是US，而是CA
	 * 如果regioncode不存在，返回"ZZ"
	 *
	 * @param countryCode
	 * @param phone
	 * @return 当号码或者countrycode不合法时，即如果无法获取regionCode，返回"ZZ"
	 */
	public static String getRegionCode(int countryCode, String phone) {
		String region = getRegionCode(getNumber(countryCode, phone));
		if (region == null) return UNKNOWN_COUNTRY;

		return region;
	}

	/**
	 * 获取号码所属的国家/地区
	 * 例如国家码同样是+1，如果后续regioncode是514的，那么regioncode不是US，而是CA
	 * 如果regioncode不存在，返回"ZZ"
	 *
	 * @param phone 必须是包含国家码的号码，如8615298765432
	 * @return
	 */
	public static String getRegionCode(long phone) {
		String region = getRegionCode(getNumber(phone));
		if (region == null) return UNKNOWN_COUNTRY;

		return region;
	}

	/**
	 * 获取号码所属的国家/地区
	 * 例如国家码同样是+1，如果后续regioncode是514的，那么regioncode不是US，而是CA
	 * 如果regioncode不存在，返回null
	 *
	 * @param number
	 * @return
	 */
	public static String getRegionCode(PhoneNumber number) {
		if (number == null) return null;
		return getInstance().getRegionCodeForNumber(number);
	}

	public static void main(String[] args) {
		System.out.println(isPossibleMobileNumber(861526339828L));
	}

	/**
	 * 根据region code 获取对应的country code
	 *
	 * @param regionCode
	 * @return 如果regioncode不合法，则返回0
	 */
	public static int getCountryCode(String regionCode) {
		return getInstance().getCountryCodeForRegion(regionCode);
	}

	/**
	 * 获取对应地区/国家的示例号码，返回 {@link CocoPhoneNumber}，参数为国家码，包含如1242等大于1000的国家码
	 *
	 * @param countryCode
	 * @return
	 */
	public static CocoPhoneNumber getExampleCocoNumber(int countryCode) {
		String phone = getExampleInternationalNumber(countryCode);
		return getCocoNumber(0, phone);
	}

	/**
	 * 获取对应地区/国家的示例号码的national格式，参数为国家码，包含如1242等大于1000的国家码
	 *
	 * @param countryCode
	 * @return
	 */
	public static String getExampleNationalNumber(int countryCode) {
		if (countryCode > 1000) {
			String region = regionMap.get(countryCode);
			String phone = getExampleNationalNumber(region);
			if (phone == null) return null;

			return phone.substring(6);
		}

		return getExampleNationalNumber(getInstance()
				.getRegionCodeForCountryCode(countryCode));
	}

	/**
	 * 获取对应地区/国家的示例号码的international格式，参数为国家码，包含如1242等大于1000的国家码
	 *
	 * @param countryCode
	 * @return
	 */
	public static String getExampleInternationalNumber(int countryCode) {
		if (countryCode > 1000) {
			String region = regionMap.get(countryCode);
			String phone = getExampleNationalNumber(region);
			if (phone == null) return null;

			return "+1 " + String.valueOf(countryCode).substring(1) + "-" + phone.substring(6);
		}

		return getExampleInternationalNumber(getInstance()
				.getRegionCodeForCountryCode(countryCode));
	}

	/**
	 * 获取对应地区/国家的示例号码的international格式
	 *
	 * @param regionCode 如'US','TW','CN'
	 * @return if there is not any example number, return null
	 */
	public static String getExampleInternationalNumber(String regionCode) {
		if (regionCode == null) return null;
		PhoneNumber number = getExamplePhoneNumber(regionCode);
		if (number == null) return null;
		return getInstance().format(number, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL);
	}

	/**
	 * 获取对应地区/国家的示例号码的national格式
	 *
	 * @param regionCode
	 * @return
	 */
	public static String getExampleNationalNumber(String regionCode) {
		if (regionCode == null) return null;
		PhoneNumber number = getExamplePhoneNumber(regionCode);
		if (number == null) return null;
		return getInstance().format(number, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
	}

	/**
	 * 获取对应地区/国家的示例号码，返回 {@link CocoPhoneNumber}
	 *
	 * @param regionCode 如'US','TW','CN'
	 * @return if there is not any example number, return null
	 */
	public static CocoPhoneNumber getExampleCocoNumber(String regionCode) {
		if (regionCode == null) return null;
		PhoneNumber number = getInstance().getExampleNumber(regionCode.toUpperCase());
		return getCocoNumber(number);
	}

	/**
	 * 获取对应地区/国家的示例号码，返回 {@link PhoneNumber}
	 *
	 * @param regionCode
	 * @return
	 */
	public static PhoneNumber getExamplePhoneNumber(String regionCode) {
		if (regionCode == null || regionCode.trim().isEmpty()) return null;
		regionCode = regionCode.toUpperCase();
		PhoneNumber number = getInstance()
				.getExampleNumberForType(regionCode.toUpperCase(), PhoneNumberUtil.PhoneNumberType.MOBILE);
		if (number == null) {
			number = getInstance()
					.getExampleNumber(regionCode.toUpperCase());
		}

		return number;
	}

	/**
	 * 检查对应的regioncode是否合法
	 *
	 * @param regionCode
	 * @return
	 */
	public static boolean isValidRegionCode(String regionCode) {
		if (regionCode == null) return false;

		if (supportRegion == null) {
			supportRegion = getInstance().getSupportedRegions();
		}

		return supportRegion.contains(regionCode.toUpperCase());
	}

	/**
	 * 判定号码是否可能是手机号码，目前手机号码/允许无法判定手机还是固定电话的号码/voip号码/UNKNOWN号码通过
	 *
	 * @param number
	 * @return
	 */
	public static boolean isPossibleMobileNumber(PhoneNumber number) {
		if (number == null) return false;
		if (!getInstance().isValidNumber(number)) return false;

		PhoneNumberUtil.PhoneNumberType type = getInstance().getNumberType(number);
		if (type == PhoneNumberUtil.PhoneNumberType.FIXED_LINE_OR_MOBILE
				|| type == PhoneNumberUtil.PhoneNumberType.MOBILE
				|| type == PhoneNumberUtil.PhoneNumberType.VOIP
				|| type == PhoneNumberUtil.PhoneNumberType.UNKNOWN) {
			return true;
		}

		return false;
	}

	/**
	 * 判定号码是否可能是手机号码，目前手机号码/允许无法判定手机还是固定电话的号码/voip号码/UNKNOWN号码通过
	 *
	 * @param countryCode
	 * @param phone
	 * @return
	 */
	public static boolean isPossibleMobileNumber(int countryCode, String phone) {
		return isPossibleMobileNumber(getNumber(countryCode, phone));
	}

	/**
	 * 判定号码是否可能是手机号码，目前手机号码/允许无法判定手机还是固定电话的号码/voip号码/UNKNOWN号码通过
	 *
	 * @param phone
	 * @return
	 */
	public static boolean isPossibleMobileNumber(long phone) {
		return isPossibleMobileNumber(getNumber(phone));
	}

	/**
	 * 获取输入格式化Fomatter
	 *
	 * @param regionCode
	 * @return
	 */
	public static AsYouTypeFormatter getAsYouTypeFormatter(String regionCode) {
		return getInstance().getAsYouTypeFormatter(regionCode);
	}


}
